package character.ai;

import action.ActionApproach;
import action.ActionAttack;
import character.MyCharacter;
import character.MyCharacterControl;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import game.CombatUtil;
import game.PlayerRelationship;

/** If the AIGeneralControl represents the senses of the character, this control represents the brain. */
public abstract class AILogicControl extends AbstractControl {
    protected MyCharacter myCharacter;
    protected MyCharacterControl characterControl;
    protected AIGeneralControl aiGeneralControl;
    protected AIState aiState = AIState.ROAM;
    
    public void takeTurn() {
        checkState();
        handleState();
    }
    
    protected void checkState() {
        switch(aiState) {
            case ROAM:
                checkRoamState();
                break;
            case ATTACK:
                checkAttackState();
                break;
            case FLEE:
                checkFleeState();
                break;
        }
    }
    
    protected void checkRoamState() {
        for(MyCharacter character : aiGeneralControl.getVisibleCharacters()) {
            if(myCharacter.getPlayer().getRelationship(character.getPlayer()) == PlayerRelationship.HOSTILE) {
                aiState = AIState.ATTACK;
            }
        }
    }
    
    protected void checkAttackState() {
        if(myCharacter.getCharacterStatus().getHitPointPercentage() <= aiGeneralControl.getAILogicSettings().getFleeAtPercent()) {
            aiState = AIState.FLEE;
        } else if(aiGeneralControl.getThreatSystem().getHighestThreatCharacter() == null) {
            aiState = AIState.ROAM;
        }
    }
    
    protected void checkFleeState() {
        if(myCharacter.getCharacterStatus().getHitPointPercentage() > aiGeneralControl.getAILogicSettings().getFleeAtPercent()) {
            aiState = AIState.ROAM;
            checkState();
        }
    }
    
    protected void handleState() {
        switch(aiState) {
            case ROAM:
                handleRoamState();
                break;
            case ATTACK:
                handleAttackState();
                break;
            case FLEE:
                handleFleeState();
                break;
        }
    }

    protected void handleRoamState() {
        characterControl.doRandomMove();
    }

    protected void handleAttackState() {
        MyCharacter topThreatChar = aiGeneralControl.getThreatSystem().getHighestThreatCharacter();
        if(!tryAbilities(topThreatChar)) {
            tryAttack(topThreatChar);
        }
    }
    
    protected boolean tryAbilities(MyCharacter topThreatChar) {
        if(topThreatChar != null) {
            return false;
        } else {
            return true; //just skip attack if no target exists
        }
    }
    
    protected void tryAttack(MyCharacter topThreatChar) {
        if(topThreatChar != null) {
            if(CombatUtil.checkAttackRange(myCharacter, topThreatChar)) {
                characterControl.queueActionLast(new ActionAttack(myCharacter, topThreatChar));
            } else {
                characterControl.queueActionLast(new ActionApproach(myCharacter, topThreatChar, myCharacter.getInventory().getEquippedWeapon().getRangePattern(), myCharacter.getInventory().getEquippedWeapon().getRangeSize()));
            }
        }
    }

    protected void handleFleeState() {
        
    }
    
    @Override
    public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        if(spatial != null) {
            myCharacter = (MyCharacter)spatial;
            characterControl = myCharacter.getControl(MyCharacterControl.class);
            aiGeneralControl = myCharacter.getControl(AIGeneralControl.class);
            aiState = AIState.ROAM;
        }
    }
    
    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {}
    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AILogicControl other = (AILogicControl) obj;
        if (this.myCharacter != other.myCharacter && (this.myCharacter == null || !this.myCharacter.equals(other.myCharacter))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 59 * hash + (this.myCharacter != null ? this.myCharacter.hashCode() : 0);
        return hash;
    }
}
